package com.encapi.framework.advice;

import com.encapi.framework.annotation.ApiCryptBody;
import com.encapi.framework.annotation.ApiEncryptBody;
import com.encapi.framework.exception.ApiCryptException;
import com.encapi.framework.exception.ExceptionUtil;
import com.encapi.framework.wrapper.ResponseDataWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.lang.reflect.Method;

/**
 * 对响应内容进行加密
 * @author xzbcode
 */
@ControllerAdvice
@SuppressWarnings("all")
public class EncryptResponseBodyAdvice<T> implements ResponseBodyAdvice<T> {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Resource
    private ResponseDataWrapper responseDataWrapper;

    @PostConstruct
    public void initInfo() {
        if (log.isInfoEnabled()) {
            log.info("[encapi] encrypt response advice init successfully.");
        }
    }

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        // 当且仅当有 EncryptRspBody 注解时才加密响应体
        Method method = methodParameter.getMethod();
        if (method != null) {
            return AnnotationUtils.findAnnotation(method, ApiEncryptBody.class) != null
                    ||  AnnotationUtils.findAnnotation(method, ApiCryptBody.class) != null;
        }
        return false;
    }

    @Override
    public T beforeBodyWrite(T data, MethodParameter method, MediaType mediaType,
                                  Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest request, ServerHttpResponse response) {
        // 调用转换器，返回加密后的数据
        try {
            return (T) this.responseDataWrapper.wrap(data, method, mediaType, request, response);
        } catch (Exception e) {
            log.error("[encapi] response data encrypt fail, cause by : {}", e.getMessage());
            throw ExceptionUtil.buildEncryptEx(e.getMessage(), e.getCause());
        }
    }


}
